﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Text.RegularExpressions;

namespace BitTorrent
{
    namespace Bencode
    {
        public class coding
        {
            private string code;

            public string Result
            {
                get { return code; }
            }

            public static string IntCode(int i) { return "i" + i + "e"; }
            public static string StrCode(string str) { return str.Length + ":" + str; }
            public static string ListCode(List<object> list)
            {
                var result = "l";

                foreach (var elem in list)
                {
                    var str = elem as string;
                    var mlist = elem as List<object>;
                    var dict = elem as SortedDictionary<object, object>;

                    if (str != null)
                    {
                        int i;
                        bool parse = Int32.TryParse(str, out i);

                        if (parse)
                            result += coding.IntCode(i);
                        else
                            result += coding.StrCode(str);
                    }
                    else if (mlist != null) result += coding.ListCode(mlist);
                    else if (dict != null) result += coding.DictCode(dict);
                }

                return result + "e";
            }
            public static string DictCode(SortedDictionary<object, object> dict)
            {
                var result = "d";

                foreach (var elem in dict)
                {
                    var key_str = elem.Key as string;

                    var val_str = elem.Value as string;
                    var val_list = elem.Value as List<object>;
                    var val_dict = elem.Value as SortedDictionary<object, object>;

                    if (key_str != null)
                    {
                        result += coding.StrCode(key_str);

                        if (val_str != null)
                        {
                            int i;
                            bool parse = Int32.TryParse(val_str, out i);

                            if (parse)
                                result += coding.IntCode(i);
                            else
                                result += coding.StrCode(val_str);
                        }
                        else if (val_list != null) result += coding.ListCode(val_list);
                        else if (val_dict != null) result += coding.DictCode(val_dict);
                    }
                }

                return result + "e";
            }

            public void ToCode(object obj)
            {
                var str = obj as string;
                var list = obj as List<object>;
                var dict = obj as SortedDictionary<object, object>;

                if (str != null)
                {
                    int i;
                    bool parse = Int32.TryParse(str, out i);

                    if (parse)
                        code = coding.IntCode(i);
                    else
                        code = coding.StrCode(str);
                }
                else if (list != null) code = coding.ListCode(list);
                else if (dict != null) code = coding.DictCode(dict);
            }
        }

        class decode
        {
            private object buf;

            public object Result
            {
                get { return buf; }
            }

            public static int IntDecode(string str)
            {
                string pattern = @"i(?<INT>\d+)e";
                var M = Regex.Match(str, pattern);

                if (M.Success)
                    return Int32.Parse(M.Groups["INT"].Value);
                else
                    throw new System.InvalidOperationException();
            }
            public static string StrDecode(string str)
            {
                string pattern = @"(?<length>\d+):(?<str>\w+)";
                var M = Regex.Match(str, pattern);

                if (M.Success)
                    return M.Groups["str"].Value.Substring(0, Int32.Parse(M.Groups["length"].Value));
                else
                    throw new System.InvalidOperationException();
            }
            public static List<object> ListDecode(string str)
            {
                return new List<object> { };
            }
            public static SortedDictionary<object, object> DictEncode(string str)
            {
                return new SortedDictionary<object, object>();
            }

            public void Encode(string str)
            {
                try { buf = decode.IntDecode(str); }
                catch (InvalidOperationException)
                {
                    try { buf = decode.StrDecode(str); }
                    catch (InvalidOperationException)
                    { buf = null; }
                }
            }
        }
    }
}
